﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading.Tasks;
using System.Threading;
using WebServerX.Logging;

namespace WebServerX
{
    public class Server
    {
        #region Properties

        public List<Client> Clients
        {
            get { return _clients; }
        }
        private List<Client> _clients = new List<Client>();

        public TcpListener Tcp
        {
            get
            {
                lock (this._tcpLock)
                {
                    return this._tcp;
                }
            }
        }
        private TcpListener _tcp = null;
        private object _tcpLock = new object();

        public Task MainTask
        {
            get { return _mainTask; }
        }
        private Task _mainTask = null;

        public List<Task> AllTasks
        {
            get
            {
                lock (this._allTasksLock)
                {
                    return this._allTasks;
                }
            }
        }
        private List<Task> _allTasks = new List<Task>();
        private object _allTasksLock = new object();

        public CancellationTokenSource CancellationToken
        {
            get { return _cancellationToken; }
        }
        private CancellationTokenSource _cancellationToken = new CancellationTokenSource();

        public bool IsRunning
        {
            get
            {
                return this.MainTask.Status != TaskStatus.Canceled;
            }
        }

        #endregion

        #region Public Methods

        public bool Init()
        {
            Logger.Log("Initializing");

            this.Shutdown();

            if (this.Tcp == null)
            {
                this._tcp = new TcpListener(IPAddress.Any, 8080);
            }

            return true;
        }

        public bool Run()
        {
            Logger.Log("Running");

            this.Tcp.Start();

            CancellationToken token = this.CancellationToken.Token;
            this._mainTask = Task.Factory.StartNew(() => { this.ServerMain(token); }, token);
            this.AllTasks.Add(this.MainTask);

            return true;
        }

        public bool Shutdown()
        {
            Logger.Log("Shutting Down / Restarting");

            if (this.Tcp != null)
            {
                this.Tcp.Stop();
                this._tcp = null;
            }

            try
            {
                Task.WaitAll(this.AllTasks.ToArray());
            }
            catch (AggregateException ex)
            {
                Logger.Log("All Tasks have cancelled (or errored...).");
                Logger.Log(ex.Message);
            }

            // this will have stopped by now because of Task.WaitAll
            if (this.MainTask != null)
                this._mainTask = null;

            return true;
        }

        public void Stop()
        {
            this.CancellationToken.Cancel();
        }

        #endregion

        #region Private Methods

        private void ServerMain(CancellationToken cancellationToken)
        {
            while (true)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                Client c = new Client(cancellationToken, this);
            }
        }

        #endregion
    }
}
